package com.enation.app.javashop.manager.api.distribution;

import com.enation.app.javashop.core.base.SettingGroup;
import com.enation.app.javashop.core.client.distribution.DistributionOrderClient;
import com.enation.app.javashop.core.client.member.ShopClient;
import com.enation.app.javashop.core.client.system.SettingClient;
import com.enation.app.javashop.core.client.trade.BillClient;
import com.enation.app.javashop.core.distribution.exception.DistributionErrorCode;
import com.enation.app.javashop.core.distribution.exception.DistributionException;
import com.enation.app.javashop.core.distribution.model.dos.DistributionDO;
import com.enation.app.javashop.core.distribution.model.dos.DistributionOrderDO;
import com.enation.app.javashop.core.distribution.model.dos.DistributionSetting;
import com.enation.app.javashop.core.distribution.model.vo.DistributionOrderVO;
import com.enation.app.javashop.core.distribution.model.vo.DistributionSellbackOrderVO;
import com.enation.app.javashop.core.distribution.service.DistributionManager;
import com.enation.app.javashop.core.distribution.service.DistributionOrderManager;
import com.enation.app.javashop.core.distribution.service.impl.DistributionOrderManagerImpl;
import com.enation.app.javashop.core.distribution.service.pattern.DistributionContext;
import com.enation.app.javashop.core.distribution.service.pattern.DistributionStrategy;
import com.enation.app.javashop.core.member.model.dos.LeaderDO;
import com.enation.app.javashop.core.member.model.dos.Member;
import com.enation.app.javashop.core.member.model.enums.CommissionTypeEnum;
import com.enation.app.javashop.core.member.service.LeaderManager;
import com.enation.app.javashop.core.member.service.MemberInviterManager;
import com.enation.app.javashop.core.member.service.MemberManager;
import com.enation.app.javashop.core.orderbill.model.dos.BillItem;
import com.enation.app.javashop.core.orderbill.model.enums.BillType;
import com.enation.app.javashop.core.orderbill.service.BillItemManager;
import com.enation.app.javashop.core.orderbill.service.SettleAccountsManager;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.ShetuanOrderDO;
import com.enation.app.javashop.core.promotion.shetuan.service.ShetuanOrderManager;
import com.enation.app.javashop.core.shop.model.vo.ShopVO;
import com.enation.app.javashop.core.statistics.util.DateUtil;
import com.enation.app.javashop.core.system.enums.WechatMiniproTemplateTypeEnum;
import com.enation.app.javashop.core.system.model.dto.MiniproMsgDataDTO;
import com.enation.app.javashop.core.system.model.dto.MiniproSendMsgDTO;
import com.enation.app.javashop.core.system.service.WechatMiniproTemplateManager;
import com.enation.app.javashop.core.trade.order.model.dos.OrderDO;
import com.enation.app.javashop.core.trade.order.model.dos.OrderProfitDO;
import com.enation.app.javashop.core.trade.order.model.enums.OrderTypeEnum;
import com.enation.app.javashop.core.trade.order.model.enums.ShipTypeEnum;
import com.enation.app.javashop.core.trade.order.model.vo.OrderSkuVO;
import com.enation.app.javashop.core.trade.order.service.OrderProfitManager;
import com.enation.app.javashop.core.trade.order.service.OrderQueryManager;
import com.enation.app.javashop.core.trade.sdk.model.OrderDetailDTO;
import com.enation.app.javashop.framework.database.Page;
import com.enation.app.javashop.framework.util.CurrencyUtil;
import com.enation.app.javashop.framework.util.JsonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 分销订单订单
 *
 * @author Chopper
 * @version v1.0
 * @Description:
 * @since v7.0
 * 2018/5/28 上午11:12
 */
@Api(description = "分销订单")
@RestController
@RequestMapping("/admin/distribution/order")
public class DistributionOrderManagerController {
    @Autowired
    private DistributionOrderManager distributionOrderManager;
    @Autowired
    private DistributionOrderClient distributionOrderClient;
    @Autowired
    private DistributionManager distributionManager;
    @Autowired
    private SettingClient settingClient;
    @Autowired
    private OrderQueryManager orderQueryManager;
    @Autowired
    private MemberInviterManager memberInviterManager;
    @Autowired
    private ShetuanOrderManager shetuanOrderManager;
    @Autowired
    private BillClient billClient;
    @Autowired
    private BillItemManager billItemManager;
    @Autowired
    private MemberManager memberManager;
    @Autowired
    private LeaderManager leaderManager;
    @Autowired
    private OrderProfitManager orderProfitManager;
    @Autowired
    private ShopClient shopClient;
    @Autowired
    private SettleAccountsManager settleAccountsManager;
    @Autowired
    private DistributionOrderManagerImpl distributionOrderManagerImpl;
    @Autowired
    private WechatMiniproTemplateManager wechatMiniproTemplateManager;


    protected final Log logger = LogFactory.getLog(this.getClass());

    @ApiOperation("结算单 分销订单查询")
    @GetMapping()
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bill_id", value = "会员结算单id", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "member_id", value = "会员id", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "page_size", value = "页码大小", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "page_no", value = "页码", required = false, paramType = "query", dataType = "int", allowMultiple = false),
    })
    public Page<DistributionOrderVO> billOrder(@ApiIgnore Integer pageNo, @ApiIgnore Integer pageSize, @ApiIgnore Integer billId, @ApiIgnore Integer memberId) throws Exception {
        try {
            return distributionOrderManager.pageDistributionOrder(pageSize, pageNo, memberId, billId);
        } catch (DistributionException e) {
            throw e;
        } catch (Exception e) {
            this.logger.error("查询结算单-》订单异常", e);
            throw new DistributionException(DistributionErrorCode.E1000.code(), DistributionErrorCode.E1000.des());
        }
    }


    @ApiOperation("结算单 分销退款订单查询")
    @GetMapping("/sellback")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bill_id", value = "结算单id", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "member_id", value = "会员id", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "page_size", value = "页码大小", required = false, paramType = "query", dataType = "int", allowMultiple = false),
            @ApiImplicitParam(name = "page_no", value = "页码", required = false, paramType = "query", dataType = "int", allowMultiple = false),
    })
    public Page<DistributionSellbackOrderVO> billSellbackOrder(@ApiIgnore Integer pageNo, @ApiIgnore Integer pageSize, @ApiIgnore Integer billId, @ApiIgnore Integer memberId) {
        try {
            return distributionOrderManager.pageSellBackOrder(pageSize, pageNo, memberId, billId);
        } catch (DistributionException e) {
            throw e;
        } catch (Exception e) {
            this.logger.error("查询结算单-》退款单异常", e);
            throw new DistributionException(DistributionErrorCode.E1000.code(), DistributionErrorCode.E1000.des());
        }
    }


    @ApiOperation("重新生成分销订单")
    @GetMapping(value = "/rebuild")
    @ApiImplicitParam(name = "order_sn", value = "订单号", required = false, paramType = "query", dataType = "string", allowMultiple = false)
    public boolean rebuild(@ApiIgnore String orderSn){
        try {
            OrderDetailDTO orderDetailDTO = orderQueryManager.getModel(orderSn);
            if(orderDetailDTO == null){
                throw new RuntimeException("订单重新生成佣金失败");
            }

            OrderDO orderDO = orderQueryManager.getModel(orderDetailDTO.getOrderId());
            Integer orderId = orderDO.getOrderId();
            BillItem billItem = billItemManager.getModelByOrderSnAndItemType(orderDO.getSn(), BillType.PAYMENT.name());
            if(billItem != null){
                if(billItem.getStatus() == 66){
                    throw new RuntimeException("已经结算的订单不能重新生成佣金");
                }
                billItemManager.delete(billItem.getId());
            }

            DistributionOrderDO distributionOrderDO = distributionOrderManager.getModel(orderId);
            if(distributionOrderDO != null){
                distributionOrderManager.delete(distributionOrderDO.getId());
            }

            List<OrderProfitDO> orderProfitList = orderProfitManager.listByOrderId(orderDO.getOrderId());
            if(orderProfitList != null && !orderProfitList.isEmpty()){
                for (OrderProfitDO orderProfitDO : orderProfitList) {
                    orderProfitManager.delete(orderProfitDO.getId());
                }
            }

            logger.debug("创建团购订单:" + orderId);
            String orderType = orderDO.getOrderType();
            if(orderType.equals(OrderTypeEnum.shetuan.name())){
                shetuanOrderManager.confirm(orderDO);
            }

            logger.debug("创建分销订单:" + orderId);
            // 买家分销信息
            int buyMemberId = orderDO.getMemberId();
            DistributionDO distributor = this.distributionManager.getDistributorByMemberId(buyMemberId);

            // 新增分销关联订单
            distributionOrderDO = new DistributionOrderDO();
            distributionOrderDO.setOrderId(orderDO.getOrderId());
            distributionOrderDO.setBuyerMemberId(buyMemberId);
            distributionOrderDO.setBuyerMemberName(distributor.getMemberName());
            distributionOrderDO.setOrderSn(orderDO.getSn());
            String setting = settingClient.get(SettingGroup.DISTRIBUTION);
            DistributionSetting ds = JsonUtil.jsonToObject(setting, DistributionSetting.class);
            distributionOrderDO.setSettleCycle((ds.getCycle() * 3600 * 24) + new Long(DateUtil.getDateline()).intValue());
            distributionOrderDO.setOrderPrice(orderDO.getNeedPayMoney());
            distributionOrderDO.setCreateTime(orderDO.getCreateTime());
            distributionOrderDO.setSellerId(orderDO.getSellerId());

            // 执行对应的策略
            DistributionStrategy distributionStrategy = distributionManager.getDistributionStrategy(orderDO, distributor);
            DistributionContext distributionContext = new DistributionContext(distributionStrategy);
            distributionContext.executeDistributors(orderDO, distributionOrderDO);

            // 计算各种佣金
            distributionManager.calAllProfit(orderDO, distributionOrderDO, distributor);

            // 保存分销订单
            this.distributionOrderClient.add(distributionOrderDO);

            // 生成结算单
            billItem = billClient.buildBillItem(orderDO.getSn(), BillType.PAYMENT);
            // 创建所有收益
            this.createAllProfit(orderDO, orderDetailDTO, billItem);
            billClient.add(billItem);
            return true;
        } catch (Exception e) {
            logger.error(e);
        }
        return false;
    }


    /**
     * 每个人的收益
     */
    private BillItem createAllProfit(OrderDO orderDO, OrderDetailDTO orderDetailDTO, BillItem billItem){
        // 订单总金额
        Integer sellerId = orderDO.getSellerId();
        Integer orderId = orderDO.getOrderId();

        Member buyerMember = memberManager.getModel(orderDO.getMemberId());
        // 区别团购订单和普通订单
        String memberTypeName = orderDO.getOrderType().equals(OrderTypeEnum.shetuan.name()) ? "团长" : "分销员";

        // 计算平台收益 订单总收入 * 佣金比例
        ShopVO shop = shopClient.getShop(sellerId);
        BigDecimal platformCommissionMoney = settleAccountsManager.countPlatformCommissionMoney(shop, orderDO.getGoodsPrice());

        // 生成平台收益记录
        OrderProfitDO platformOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, null, null, BigDecimal.valueOf(shop.getShopCommission()),
                platformCommissionMoney, CommissionTypeEnum.PLATFORM, "平台", 1,buyerMember);
        orderProfitManager.add(platformOrderProfitDO);

        // 计算分销金额
        DistributionOrderDO distributionOrderDO = distributionOrderManagerImpl.getModelByOrderSn(orderDetailDTO.getSn());
        Integer memberIdLv1 = distributionOrderDO.getMemberIdLv1();
        Integer memberIdLv2 = distributionOrderDO.getMemberIdLv2();
        Integer inviterMemberId = distributionOrderDO.getInviterMemberId();
        Integer subsidyMemberId = distributionOrderDO.getSubsidyMemberId();
        Double invitePoint = distributionOrderDO.getInvitePoint();
        Double grade1Rebate = distributionOrderDO.getGrade1Rebate();
        Double grade2Rebate = distributionOrderDO.getGrade2Rebate();
        Double inviteMoney = distributionOrderDO.getInviteRebate();
        Double subsidyMoney = distributionOrderDO.getSubsidyRebate();

        if(memberIdLv1 != null){
            Member member = memberManager.getModel(memberIdLv1);
            if(member != null){
                OrderProfitDO leaderOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, memberIdLv1, member.getNickname(),
                        BigDecimal.valueOf(distributionOrderDO.getLv1Point()), BigDecimal.valueOf(grade1Rebate),
                        CommissionTypeEnum.DISTRIBUTION, memberTypeName, 1,buyerMember);
                orderProfitManager.add(leaderOrderProfitDO);
            }
        }
        if(memberIdLv2 != null){
            Member member = memberManager.getModel(memberIdLv2);
            if(member != null){
                OrderProfitDO leaderOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, memberIdLv2, member.getNickname(),
                        BigDecimal.valueOf(distributionOrderDO.getLv2Point()), BigDecimal.valueOf(grade2Rebate),
                        CommissionTypeEnum.DISTRIBUTION, memberTypeName, 2,buyerMember);
                orderProfitManager.add(leaderOrderProfitDO);
            }
        }
        if(inviterMemberId != null){
            Member member = memberManager.getModel(inviterMemberId);
            if(member != null){
                OrderProfitDO inviterOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, inviterMemberId, member.getNickname(),
                        BigDecimal.valueOf(invitePoint), BigDecimal.valueOf(inviteMoney), CommissionTypeEnum.INVITER, memberTypeName, 1,buyerMember);
                orderProfitManager.add(inviterOrderProfitDO);
            }
        }
        if(subsidyMemberId != null){
            Member member = memberManager.getModel(subsidyMemberId);
            if(member != null){
                OrderProfitDO subsidyOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, subsidyMemberId, member.getNickname(),
                        BigDecimal.valueOf(distributionOrderDO.getSubsidyPoint()), BigDecimal.valueOf(subsidyMoney),
                        CommissionTypeEnum.SUBSIDY, memberTypeName, 1, buyerMember);
                orderProfitManager.add(subsidyOrderProfitDO);
            }
        }

        // 计算自提点佣金
        double leaderMoney = 0;
        String orderType = orderDO.getOrderType();
        if(orderType.equals(OrderTypeEnum.shetuan.name())){
            // 计算自提点佣金
            ShetuanOrderDO shetuanOrderDO = shetuanOrderManager.getByOrderId(orderId);
            if(shetuanOrderDO != null){
                Double commissionRate = shetuanOrderDO.getCommissionRate();
                leaderMoney = shetuanOrderDO.getLeaderCommission();
                Integer leaderMemberId = shetuanOrderDO.getLeaderMemberId();
                if(leaderMemberId != null && ShipTypeEnum.SELF.getIndex().equals(orderDO.getShippingType())){
                    Member leaderMember = memberManager.getModel(leaderMemberId);
                    if(leaderMember != null){
                        LeaderDO leaderDO = leaderManager.getByMemberId(leaderMember.getMemberId());
                        if(leaderDO != null && leaderDO.getAuditStatus() == 2 && leaderDO.getStatus() == 1){
                            OrderProfitDO leaderOrderProfitDO = this.buildOrderProfit(orderDO, orderDetailDTO, leaderMember.getMemberId(),
                                    leaderMember.getNickname(), BigDecimal.valueOf(commissionRate), BigDecimal.valueOf(leaderMoney),
                                    CommissionTypeEnum.SITE, "自提点", 1,buyerMember);
                            orderProfitManager.add(leaderOrderProfitDO);
                        }
                    }
                }
            }
        }

        // 计算卖家结算金额  注意!!! 补贴属于平台补贴 不要在下面计算
        // Double totalOrderPrice = orderDO.getOrderPrice();
        Double totalOrderPrice = orderDO.getGoodsPrice();
        double distributionMoney = CurrencyUtil.add(grade1Rebate, grade2Rebate);
        double sellerSettleMoney = new BigDecimal(totalOrderPrice).subtract(platformCommissionMoney)
                .subtract(new BigDecimal(leaderMoney)).subtract(new BigDecimal(distributionMoney))
                .subtract(new BigDecimal(inviteMoney)).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue();

        billItem.setPlatformMoney(platformCommissionMoney);
        billItem.setSellerMoney(BigDecimal.valueOf(sellerSettleMoney));
        billItem.setLeaderMoney(BigDecimal.valueOf(leaderMoney));
        billItem.setDistributionMoney(BigDecimal.valueOf(distributionMoney));
        billItem.setLv1Money(BigDecimal.valueOf(grade1Rebate));
        billItem.setLv2Money(BigDecimal.valueOf(grade2Rebate));
        billItem.setInviteMoney(BigDecimal.valueOf(inviteMoney));
        billItem.setSubsidyMoney(BigDecimal.valueOf(subsidyMoney));
        return billItem;
    }


    /**
     * 保存收益记录
     */
    private OrderProfitDO buildOrderProfit(OrderDO orderDO, OrderDetailDTO orderDetailDTO, Integer memberId, String memberName,
                                           BigDecimal commissionRate, BigDecimal commissionMoney,
                                           CommissionTypeEnum commissionTypeEnum, String memberTypeName, Integer spreadWay,Member buyerMember) {
        String itemsJson = orderDO.getItemsJson();
        List<OrderSkuVO> skuList = JsonUtil.jsonToList(itemsJson,OrderSkuVO.class);

        OrderProfitDO orderProfitDO = new OrderProfitDO();
        orderProfitDO.setMemberId(memberId);
        orderProfitDO.setMemberName(memberName);

        orderProfitDO.setProfitNo(String.valueOf(com.enation.app.javashop.framework.util.DateUtil.getDateline()));
        orderProfitDO.setProfitName(this.getGoodsName(skuList));
        orderProfitDO.setBuyerId(orderDO.getMemberId());
        orderProfitDO.setBuyerName(buyerMember.getNickname());
        orderProfitDO.setOrderId(orderDO.getOrderId());
        orderProfitDO.setOrderSn(orderDO.getSn());
        orderProfitDO.setSellerId(orderDO.getSellerId());
        orderProfitDO.setSellerName(orderDetailDTO.getSellerName());
        orderProfitDO.setOrderPrice(BigDecimal.valueOf(orderDO.getGoodsPrice()));
        orderProfitDO.setOrderType(orderDO.getOrderType());
        orderProfitDO.setOrderTypeName(this.countOrderTypeName(orderDO.getOrderType()));
        orderProfitDO.setCommissionRate(commissionRate);
        orderProfitDO.setCommissionMoney(commissionMoney);
        orderProfitDO.setOrderStatus(orderDO.getOrderStatus());
        orderProfitDO.setOrderStatusName(orderDetailDTO.getOrderStatusText());
        orderProfitDO.setCommissionType(commissionTypeEnum.getIndex());
        orderProfitDO.setCommissionTypeName(commissionTypeEnum.getText());
        String goodsImage = skuList.get(0).getGoodsImage();
        orderProfitDO.setOrderImgs(goodsImage);
        orderProfitDO.setMemberTypeName(memberTypeName);
        orderProfitDO.setSpreadWay(spreadWay);
        orderProfitDO.setCreateTime(orderDO.getCreateTime());
        return orderProfitDO;
    }


    private String countOrderTypeName(String orderType) {
        String orderTypeName = "普通订单";
        if(OrderTypeEnum.pintuan.name().equals(orderType)){
            orderTypeName = "拼团订单";
        }else if(OrderTypeEnum.shetuan.name().equals(orderType)){
            orderTypeName = "团购订单";
        }
        return orderTypeName;
    }

    // 获取订单商品名称
    private String getGoodsName(List<OrderSkuVO> skuList){
        OrderSkuVO orderSkuVO = skuList.get(0);
        String goodsName = orderSkuVO.getName();
        if(goodsName.length() >= 20){
            goodsName = goodsName.substring(0, 17) + "...";
        }
        return goodsName;
    }


    @ApiOperation(value = "模拟发送小程序订阅消息")
    @GetMapping("/send")
    public void send(String openid) {
        // 封装data参数
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("character_string3", MiniproMsgDataDTO.build("2020000000001"));
        // 下单用户
        dataMap.put("thing7", MiniproMsgDataDTO.build("测试用户"));
        //订单金额
        dataMap.put("amount2", MiniproMsgDataDTO.build("10"));
        //预估佣金
        dataMap.put("amount6", "0.8");
        //备注 你获得了一笔+${推广类型}+的+${订单类型}+${佣金类型}1直推 2间推
        dataMap.put("thing5", MiniproMsgDataDTO.build("你获得了一笔直推的社区团购团长佣金(测试)"));

        // 发送消息
        MiniproSendMsgDTO miniproSendMsgDTO = new MiniproSendMsgDTO();
        miniproSendMsgDTO.setOpenId(openid);
        miniproSendMsgDTO.setDataMap(dataMap);
        miniproSendMsgDTO.setPageParams("/pages/spread/profit/profit");
        miniproSendMsgDTO.setTemplateTypeEnum(WechatMiniproTemplateTypeEnum.PROFITE_NOTICE);
        wechatMiniproTemplateManager.send(miniproSendMsgDTO);
    }
}
